package csc.daonjpa.java.controller;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import share.Constant;
import csc.daonjpa.java.domain.Customer;
import csc.daonjpa.java.domain.JSONResponse;
import csc.daonjpa.java.domain.Transaction;
import csc.daonjpa.java.domain.TransactionState;
import csc.daonjpa.java.service.CustomerService;
import csc.daonjpa.java.service.LogService;
import csc.daonjpa.java.service.TransactionService;
import csc.daonjpa.java.service.TransactionStateService;

@Controller
public class TransactionController {
	
	@Autowired
	private TransactionStateService transactionStateService;
	
	@Autowired
	private TransactionService transactionService;

	@Autowired
	private CustomerService customerService;
	
	@Autowired
	private LogService logService;
	
	/**
	 * @return the transactionStateService
	 */
	public TransactionStateService getTransactionStateService() {
		return transactionStateService;
	}

	/**
	 * @param transactionStateService the transactionStateService to set
	 */
	public void setTransactionStateService(
			TransactionStateService transactionStateService) {
		this.transactionStateService = transactionStateService;
	}

	@RequestMapping(value = {"createTransaction"})
	public @ResponseBody JSONResponse createTransaction(HttpServletRequest request) {
		JSONResponse validationResponse = new JSONResponse();
		
		String optionChooseAccount = request.getParameter(Constant.PARAM_OPTION_CHOOSE_ACCOUNT);
		String amount = request.getParameter(Constant.PARAM_AMOUNT);
		long longAmount = Long.parseLong(amount);
		String description = request.getParameter(Constant.PARAM_DESCRIPTION);
		Long customerId = (Long) request.getSession().getAttribute(Constant.SESSION_ATR_CUSTOMER_ID);
		//lay ngay hien tai
		Date date = new Date();
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String dateString = dateFormat.format(date);
		
		String targetAccountNumber = Constant.STR_EMPTY;
		if (Constant.PARAM_VALUE_FROM_INPUT_ACCOUNT.equals(optionChooseAccount)) {
			targetAccountNumber = request.getParameter(Constant.PARAM_TARGET_ACCOUNT_NUMBER);
		} else if (Constant.PARAM_VALUE_FROM_LIST_ACCOUNT.equals(optionChooseAccount)) {
			targetAccountNumber = request.getParameter(Constant.PARAM_SELECT_TARGET_ACCOUNT_NUMBER);
		}
		
		if (transactionService.isTransferable(customerId, amount, dateString)) {
			dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			dateString = dateFormat.format(date);
			Customer sendCustomer = customerService.getCustomer(customerId);
			Customer receivedCustomer = customerService.getCustomerByAccountNumber(targetAccountNumber);
			validationResponse = validateTransaction(longAmount, sendCustomer,
					receivedCustomer);
			
			//if validate with no error, isSuccess() will return true :(
			if (validationResponse.isSuccess()) {
				TransactionState state = transactionStateService.getTransactionState(amount);
				if (TransactionState.APPROVED_TRANSACTION.compareTo(state.getStateId()) == 0) {
					//right now add amount to receiver account and subtract the same to sender
					transactionService.recalculateAmount(sendCustomer, receivedCustomer, amount);					
				} else if (TransactionState.PENDING_TRANSACTION.compareTo(state.getStateId()) == 0){
					//just subtract the amount from sender amount, till the transaction be approved :3
					sendCustomer.setAmount(sendCustomer.getAmount() - longAmount);
				}
				
				Transaction transaction = new Transaction();
				transaction.setAmount(longAmount);
				transaction.setDescription(description);
				transaction.setTransactionState(state);
				transaction.setDate(dateString);
				transaction.setSendCustomer(sendCustomer);
				transaction.setReceivedCustomer(receivedCustomer);
				//call transaction service to insert this transaction to DB
				if (transactionService.addTransaction(transaction)) {
					validationResponse.setSuccess(true);				
					if (transaction.getTransactionState().getStateId() == TransactionState.PENDING_TRANSACTION) {
						logService.createLog(
								"Created transaction with amount is "
										+ longAmount
										+ ", waiting to be approved",
								customerId);
					} else if (transaction.getTransactionState().getStateId() == TransactionState.APPROVED_TRANSACTION){
						logService.createLog(
								"Created transaction with amount is "
										+ longAmount
										+ ", transaction completed",
								customerId);
					}
				}
				
			}
		} else {
			validationResponse.setSuccess(false);
			validationResponse.appendMessage("Sorry, you reach the maximum number of transfer or the maximum total transferred amount of money per day!");
		}
		
		return validationResponse;
	}

	private JSONResponse validateTransaction(long longAmount,
			Customer sendCustomer, Customer receivedCustomer) {
		boolean isValidateSuccess = true;
		JSONResponse response = new JSONResponse();
		// restrict if receivedCustomer is not exist, or the sender send money to his/herself :3
		if (null == receivedCustomer) {
			isValidateSuccess  = false;
			response.appendMessage("Target account is not valid!");
		}
		else if(sendCustomer.getId().compareTo(receivedCustomer.getId())==0){
			isValidateSuccess  = false;
			response.appendMessage("Target account is your own account!");
		}
		//also restrict if sender send an amount bigger than his balance, oh poor man ! :v
		if (longAmount > sendCustomer.getAmount()) {
			isValidateSuccess  = false;
			response.appendMessage("The inputed amount bigger than your balance!");
		}
		//and hell now the receivedCustomer is inactive...
		if (!receivedCustomer.isActive()) {
			isValidateSuccess  = false;
			response.appendMessage("Target account is locked!");
		}
		response.setSuccess(isValidateSuccess);
		return response;
	}
	
	@RequestMapping(value={"history"})
	public String customerHistory(Model model, HttpServletRequest request){
		Long customerLoginId = (Long) request.getSession().getAttribute(Constant.SESSION_ATR_CUSTOMER_ID);
		Long customerId = (Long) request.getSession().getAttribute(Constant.SESSION_ATR_CUSTOMER_ID);
		model.addAttribute(Constant.MODEL_OBJ_SENT_TRANSACTION, transactionService.getTransferedTransaction(customerLoginId));
		model.addAttribute(Constant.MODEL_OBJ_RECEIVED_TRANSACTION, transactionService.getReceivedTransaction(customerLoginId));
		model.addAttribute(Constant.MODEL_OBJ_CUSTOMER, customerService.getCustomer(customerId));
		return Constant.VIEW_HISTORY;
	}
	
	@RequestMapping(value={"moneyTransfer"})
	public String toMoneyTransfer(Model model, HttpServletRequest request){
		Long customerId = (Long) request.getSession().getAttribute(Constant.SESSION_ATR_CUSTOMER_ID);
		List<Customer> lstCustomer = transactionService.getReceivedCustomer(customerId);
		
		//Lay ra so lan & luong tien da giao dich trong ngay
		Date date = new Date();
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String dateString = dateFormat.format(date);
		List<Transaction> lstTransaction = transactionService.getTransactions(customerId, dateString);
		
		long amountSum = 0;
		if (null != lstTransaction) {
			for(Transaction trans : lstTransaction){
				amountSum = amountSum + trans.getAmount();
			}
		}
		
		model.addAttribute(Constant.MODEL_OBJ_CUSTOMER_LIST, lstCustomer);
		model.addAttribute(Constant.MODEL_OBJ_CUSTOMER, customerService.getCustomer(customerId));
		model.addAttribute(Constant.MODEL_OBJ_NUMBER_OF_TRANSACTION,  lstTransaction.size());
		model.addAttribute(Constant.MODEL_OBJ_TRANSFERED_AMOUNT, amountSum);
		
		return Constant.VIEW_MONEY_TRANSFER;
	}
}
